﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using LinqToBing.Bing.Wrapper;
using LinqToBing.Bing.Wrapper.Results;

namespace LinqToBing.Bing.Linq
{
    public class LiveSearchContext
    {
        private static string AppID = string.Empty;

        public LiveSearchContext(string appID)
        {
            AppID = appID;
        }

        // Executes the expression tree that is passed to it.
        internal static object Execute(Expression expression, bool IsEnumerable)
        {
            // The expression must represent a query over the data source.
            if (!IsQueryOverDataSource(expression))
                throw new InvalidProgramException("No query over the data source was specified.");

            // Find the call to Where() and get the lambda expression predicate.
            InnermostWhereFinder whereFinder = new InnermostWhereFinder();
            MethodCallExpression whereExpression = whereFinder.GetInnermostWhere(expression);
            LambdaExpression lambdaExpression = (LambdaExpression)((UnaryExpression)(whereExpression.Arguments[1])).Operand;

            // Send the lambda expression through the partial evaluator.
            lambdaExpression = (LambdaExpression)Evaluator.PartialEval(lambdaExpression);

            // Get the place name(s) to query the Web service with.
            ResultFinder lf = new ResultFinder(lambdaExpression.Body);
            List<string> locations = lf.searchQueries;
            if (locations.Count == 0)
                throw new InvalidQueryException("You must specify at least one place name in your query.");

            // Call the Web service and get the results.
            LiveSearchResultBase[] results = SearchHelper.ExecuteSearch(AppID, Wrapper.Enums.SearchTypeEnum.Web, locations);
                //DoSearch(Wrapper.Enums.SearchTypeEnum.Web, locations);
                //WebServiceHelper.GetPlacesFromTerraServer(locations);

            // Copy the IEnumerable places to an IQueryable.
            IQueryable<LiveSearchResultBase> queryablePlaces = results.AsQueryable<LiveSearchResultBase>();

            // Copy the expression tree that was passed in, changing only the first
            // argument of the innermost MethodCallExpression.
            ExpressionTreeModifier treeCopier = new ExpressionTreeModifier(queryablePlaces);
            Expression newExpressionTree = treeCopier.Visit(expression);

            // This step creates an IQueryable that executes by replacing Queryable methods with Enumerable methods.
            if (IsEnumerable)
                return queryablePlaces.Provider.CreateQuery(newExpressionTree);
            else
                return queryablePlaces.Provider.Execute(newExpressionTree);
        }

        private static bool IsQueryOverDataSource(Expression expression)
        {
            // If expression represents an unqueried IQueryable data source instance,
            // expression is of type ConstantExpression, not MethodCallExpression.
            return (expression is MethodCallExpression);
        }

        public IQueryable<LiveSearchResultWeb> GetWeb()
        {
            return null;
        }

        public IQueryable<LiveSearchResultWeb> Web
        {
            get
            {
                return GetWeb();
            }
        }

    }
}
